package com.jh.fcsm.common.aspect;

import com.alibaba.fastjson2.JSONObject;
import com.jh.fcsm.common.exception.ServiceException;
import com.jh.fcsm.common.redis.RedisUtil;
import com.jh.fcsm.util.security.MD5Utils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 防止重复提交注解实现
 *
 * @author szx
 */
@Component
@Aspect
public class RepeatSubAop {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 环绕带注解@RepeatSubAnnotation的方法做aop
     */
    @Around(value = "@annotation(com.jh.fcsm.common.annotation.RepeatSubAnnotation)")
    public Object repeatSub(ProceedingJoinPoint joinPoint) throws Throwable {

        String repeatSubKey = "";
        try {
            //取用户信息和请求路径
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();

            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            String[] paramNames = methodSignature.getParameterNames();// 参数名
            //读取参数 md5后做为重复提交判断的key
            if (paramNames != null && paramNames.length > 0) {
                Object[] args = joinPoint.getArgs();// 参数值
                Map<String, Object> params = new HashMap<>();
                for (int i = 0; i < paramNames.length; i++) {
                    Object value = args[i];
                    if (value instanceof Serializable) {
                        params.put(paramNames[i], value);
                    }
                }
                //对单独方法生效
                repeatSubKey = "wodai:repeat:" + MD5Utils.getMD5Str(request.getRequestURL().toString() + JSONObject.toJSONString(params));
            }
        } catch (Exception e) {

        }
        //判断为重复提交给出提示
        if (!StringUtils.isEmpty(repeatSubKey)) {
            Object value = redisUtil.get(repeatSubKey);
            if (value != null && value.toString().equals("1")) {
                throw new ServiceException("重复操作");
            }
            //设置5s后自动过期避免死锁
            redisUtil.set(repeatSubKey, "1", 5);
        }
        try {
            Object object = joinPoint.proceed();// 执行原方法
            if (!StringUtils.isEmpty(repeatSubKey)) {
                //执行完成删除key
                redisUtil.del(repeatSubKey);
            }
            return object;
        } catch (Exception e) { // 方法执行失败
            throw e;
        }
    }
}
